package com.zynn.api.yinian.zuul.filter;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.zynn.api.yinian.zuul.constant.LoginUserConstant;
import com.zynn.api.yinian.zuul.constant.UrlConstant;
import com.zynn.api.yinian.zuul.util.ZuulUtil;
import com.zynn.common.core.dto.LoginAndRegisterResultDTO;
import com.zynn.common.core.utils.MD5Utils;
import com.zynn.common.pojo.result.Result;
import com.zynn.common.pojo.result.ResultEnum;
import com.zynn.common.pojo.result.ResultUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import redis.clients.jedis.JedisCluster;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * filterType：返回一个字符串代表过滤器的类型，在zuul中定义了四种不同生命周期的过滤器类型，具体如下：
 * pre：路由之前
 * routing：路由之时
 * post： 路由之后
 * error：发送错误调用
 * <p>
 * <p>
 * filterOrder：过滤的顺序
 * shouldFilter：这里可以写逻辑判断，是否要过滤，本文true,永远过滤。
 * run：过滤器的具体逻辑。可用很复杂，包括查sql，nosql去判断该请求到底有没有权限访问。
 * <p>
 * 外部http请求到达api网关服务的时候，首先它会进入第一个阶段pre，在这里它会被pre类型的过滤器进行处理。该类型过滤器的主要目的是在进行请求路由之前做一些前置加工，比如请求的校验等。
 * 在完成了pre类型的过滤器处理之后，请求进入第二个阶段routing，也就是之前说的路由请求转发阶段，请求将会被routing类型的处理器处理。这里的具体处理内容就是将外部请求转发到具体服务实例上去的过程，
 * 当服务实例请求结果都返回之后，routing阶段完成，请求进入第三个阶段post。此时请求将会被post类型的过滤器处理，这些过滤器在处理的时候不仅可以获取到请求信息，还能获取到服务实例的返回信息，所以在post类型的过滤器中，我们可以对处理结果进行一些加工或转换等内容。
 * 另外，还有一个特殊的阶段error，该阶段只有在上述三个阶段中发生异常的时候才会触发，但是它的最后流向还是post类型的过滤器，因为它需要通过post过滤器将最终结果返回给请求客户端（对于error过滤器的处理，在spring cloud zuul的过滤链中实际上有一些不同）
 */
@Slf4j
@Component
public class LoginFilter extends ZuulFilter {

    @Autowired
    private JedisCluster jedisCluster;

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public String filterType() {
        //表明是路由之后才需要进行过滤
        //这个路由会在token filter之后进行
        //此时已经获取到微服务的返回值
        return FilterConstants.POST_TYPE;
    }

    @Override
    public int filterOrder() {
        //最开始就过滤
        return 0;
    }

    @Override
    public boolean shouldFilter() {
        //获取上下文信息
        String servletPath = RequestContext.getCurrentContext().getRequest().getServletPath();
        //判断如果包含这些路径就过滤
        return UrlConstant.matchPath(UrlConstant.PASS_SERVLET_PATHS, servletPath);
    }

    /**
     * @return 此方法返回值 看了底层没啥实际作用 为null即可
     */
    @Override
    public Object run() {
        RequestContext currentContext = RequestContext.getCurrentContext();
        HttpServletRequest request = currentContext.getRequest();
        HttpServletResponse response = currentContext.getResponse();
        Result result = ZuulUtil.getResponseResult(currentContext);
        //调用登录接口异常
        if (result == null) {
            currentContext.setSendZuulResponse(false);
            currentContext.setResponseBody(JSON.toJSONString(ResultUtil.fail(ResultEnum.SERVICE_ERROR)));
            return null;
        }
        //调用接口成功,但是登录失败
        if (result.getCode() < 0) {
            currentContext.setSendZuulResponse(false);
            currentContext.setResponseBody(JSON.toJSONString(result));
            return null;
        }
        //用户未注册
        if(result.getData()==null) {
            currentContext.setSendZuulResponse(false);
            currentContext.setResponseBody(JSON.toJSONString(result));
            return null;
        }
        //将信息设置到返回的header中
        LoginAndRegisterResultDTO user = JSONObject.parseObject(result.getData().toString(), LoginAndRegisterResultDTO.class);
        String md5Str = MD5Utils.md5Encrypt(user.getOpenId());
        response.setHeader(LoginUserConstant.USER_INFO_KEY,md5Str);
        jedisCluster.set(md5Str,result.getData().toString());
        //返回登录用户的信息
        user.setOpenId("");
        Result success = ResultUtil.success(user);
        currentContext.setSendZuulResponse(true);
        String jsonResult = JSON.toJSONString(success);
        currentContext.setResponseBody(jsonResult);
        return null;
    }


}
